package entity

import (
	"sync"
	"time"

	"gitee.com/night-tc/gobige/global"
	"gitee.com/night-tc/gobige/logger"
	. "gitee.com/night-tc/gobige/msghandler"
	"gitee.com/night-tc/gobige/threads"
)

type IEntities interface {
	//这个需要子类实现
	IMsgHandler
	//这个需要子类实现
	IDelayCall
	//Loop时的时间
	GetNowTime() time.Time
	// //这个需要子类实现
	// ITime

	/* 生存周期函数 */

	//初始化
	Init() error
	//循环调用
	Loop()
	// //循环调用中间
	// Looping()
	// //循环调用结尾
	// Looped()

	//销毁
	Destroy()
	// //发生异常的时候
	// OnPanic(err error)
	// //自运行协程的函数
	// GoRun(ctx context.Context)

	/* 集合逻辑 */

	//获取子对象
	GetEntity(eid uint64) IEntity
	// 获取子对象使用DBID
	GetEntityByDBID(dbid uint64, etype string) IEntity
	//创建子对象
	CreateEntity(etype string, eid, dbid uint64, fly bool, param ...interface{}) (result IEntity, err error)
	//销毁子对象
	DestroyEntity(eid uint64) error
	// 删除指定服务器上的子对象; 删除后，会调用callbackf
	DestroyEntityByStype(eid uint64, stype global.ServerTypeEnum, callbackf global.RouteCallBackF) error
	//遍历所有成员
	Range(f func(k, v interface{}) bool)
	//按分组遍历组内所有成员
	RangeByGroup(gp string, f func(k, v any) bool)
	//按类型遍历组内所有成员
	RangeByType(etype string, f func(k, v any) bool)
	// 添加子对象loop信号量
	AddChan(uint64, ITime)
	// 移除子对象loop信号量
	ReChan(uint64, ITime)

	/* 其他接口 */

	//字符串化信息
	String() string

	/* 属性 */

	//本空间的ID
	GetEntityID() uint64
	//操作子协程的管理器
	GetThreadGo() *threads.ThreadGo
	// //获取路由器
	// GetMsgHandler() *MsgHandlers
}

////////////////////////////////////////////////////////
/* 生存周期函数 */

// 初始化
func (this *Entities) Init() error {
	//消息注册
	this.realPtr.RegMsgProc(&EntitiesMsgProc{this.realPtr})
	return nil
}

// 循环调用
func (this *Entities) Loop() {
	if !this.isMutilThread {
		n := this.realPtr.GetNowTime()
		this.realPtr.Range(func(k, v interface{}) bool {
			v.(ITime).SetNowTime(n)
			v.(IEntity).mainLoop()
			return true
		})
	} else {
		n := this.realPtr.GetNowTime()
		this.entitiesChan.Range(func(k, v interface{}) bool {
			v.(ITime).SetTickerNow(n)
			return true
		})
	}

}

// 销毁 会等所有子协程结束
func (this *Entities) Destroy() {
	this.entities.Range(func(key, value any) bool {
		if v, ok := value.(IEntity); ok {
			this.delEntity(v)
			v.EnterDestroy()
		} else {
			logger.Warnf("entities Destroy %s != IEntity", value)
		}
		return true
	})
	logger.Info("Entities Destroy")
	this.thgo.CloseWait()
}

/* 生存周期函数 */
////////////////////////////////////////////////////////
/* 集合逻辑 */

// 获取子对象
func (this *Entities) GetEntity(eid uint64) IEntity {
	if result, ok := this.entities.Load(eid); ok {
		return result.(IEntity)
	} else {
		return nil
	}
}

// 获取子对象使用DBID
func (this *Entities) GetEntityByDBID(dbid uint64, etype string) IEntity {
	if eli, ok := this.entitiesByDBID.Load(etype); ok {
		if result, ok := eli.(*sync.Map).Load(dbid); ok {
			return result.(IEntity)
		} else {
			return nil
		}
	} else {
		return nil
	}
}

/*
创建子对象
etype:实例对象类型
eid:实例的唯一ID
dbid:实例持久化的唯一ID，如果没有持久化可以使用eid一样
fly:是否为自由对象，不是自由对象时，需要redis里注册路由
*/
func (this *Entities) CreateEntity(etype string, eid, dbid uint64, fly bool, param ...interface{}) (result IEntity, err error) {
	if eid == 0 {
		eid = global.GetSrvInst().GetNewEID()
	}
	if _, ok := this.entities.Load(eid); ok {
		return nil, ErrNtt_EID_Exist.NewErr(nil, eid)
	}
	result = GetTypeMgr().NewEntity(etype)
	err = result.OnCreated(etype, eid, dbid, result, this.realPtr, fly, param...)
	if err != nil {
		return nil, err
	}
	this.addEntity(result)
	if this.isMutilThread {
		//启动子协程
		thgo := threads.NewSubThreadGo(this.thgo)
		result.setThgo(thgo)
		thgo.Go(result.GoRun)
	} else {
		//因为没有子协程，所以子对象收消息需要在本消息处理里进行
		result.SetMainHander(this.realPtr)
	}

	return result, nil
}

// 销毁子对象
func (this *Entities) DestroyEntity(eid uint64) error {
	v, ok := this.entities.Load(eid)
	if !ok {
		return ErrNtt_EID_Not_Exist.NewErr(nil, eid)
	}
	e := v.(IEntity)
	this.delEntity(e)
	//销毁需要在帧尾做，确保一些逻辑做完了再销毁，但在集合中已找不到这个对象了
	this.realPtr.CallDelay(e.EnterDestroy)

	return nil
}

// 删除指定服务器上的子对象; 删除后，会调用callbackf
func (this *Entities) DestroyEntityByStype(eid uint64, stype global.ServerTypeEnum, callbackf global.RouteCallBackF) error {
	v, ok := this.entities.Load(eid)
	if !ok {
		return ErrNtt_EID_Not_Exist.NewErr(nil, eid)
	}
	e, ok := v.(IEntityReal)
	if !ok {
		return ErrNtt_EID_Not_Exist.NewErr(nil, eid)
	}
	if err := e.DestroyEntityByStype(stype, callbackf); err != nil {
		return err
	}
	return nil
}

// 遍历所有成员
func (this *Entities) Range(f func(k, v interface{}) bool) {
	this.entities.Range(f)
}

// 按分组遍历组内所有成员
func (this *Entities) RangeByGroup(gp string, f func(k, v any) bool) {
	if l, ok := this.entitiesGroup.Load(gp); ok {
		l.(*sync.Map).Range(f)
	}
}

// 按类型遍历组内所有成员
func (this *Entities) RangeByType(etype string, f func(k, v any) bool) {
	if l, ok := this.entitiesByType.Load(etype); ok {
		l.(*sync.Map).Range(f)
	}
}

// 添加子对象loop信号量
func (this *Entities) AddChan(eid uint64, v ITime) {
	this.entitiesChan.Store(eid, v)
}

// 移除子对象loop信号量
func (this *Entities) ReChan(eid uint64, v ITime) {
	this.entitiesChan.CompareAndDelete(eid, v)
}

/* 集合逻辑 */
////////////////////////////////////////////////////////
/* 私有函数 */

// 添加对象
func (this *Entities) addEntity(ntt IEntity) {
	this.entities.Store(ntt.GetEntityID(), ntt)
	if ntt.GetDBID() != 0 {
		//按类型分组，dbid为KEY
		var t *sync.Map
		if tmp, ok := this.entitiesByDBID.Load(ntt.GetType()); ok {
			t = tmp.(*sync.Map)
		} else {
			t = &sync.Map{}
			this.entitiesByDBID.Store(ntt.GetType(), t)
		}
		t.Store(ntt.GetDBID(), ntt)
	}
	{
		//按类型分组，eid为KEY
		var t *sync.Map
		if tmp, ok := this.entitiesByType.Load(ntt.GetType()); ok {
			t = tmp.(*sync.Map)
		} else {
			t = &sync.Map{}
			this.entitiesByType.Store(ntt.GetType(), t)
		}
		t.Store(ntt.GetEntityID(), ntt)
	}
	this.entityCount.Add(1)
}

// 销毁子对象
func (this *Entities) delEntity(e IEntity) {
	this.entities.Delete(e.GetEntityID())
	if e.GetDBID() != 0 {
		//按类型分组，dbid为KEY
		if it, ok := this.entitiesByDBID.Load(e.GetType()); ok {
			it.(*sync.Map).Delete(e.GetDBID())
		}
	}

	//按类型分组，eid为KEY
	if it, ok := this.entitiesByType.Load(e.GetType()); ok {
		it.(*sync.Map).Delete(e.GetEntityID())
	}
	this.delEntityGroup(e)
	this.entityCount.Add(-1)
}

// 删除对象分组
func (this *Entities) delEntityGroup(e IEntity) {
	e.GetGroups().Range(func(key, val interface{}) bool {
		if it, ok := this.entitiesGroup.Load(key); ok {
			t := it.(*sync.Map)
			t.Delete(e.GetEntityID())
		}
		return true
	})
}

/* 私有函数 */
////////////////////////////////////////////////////////
////////////////////////////////////////////////////////
////////////////////////////////////////////////////////
